package cn.sccl.dirms.topo.discovery;

import cn.sccl.common.util.DateUtil;
import cn.sccl.dirms.topo.discovery.model.DeviceInfo;
import cn.sccl.dirms.topo.discovery.model.DiscoveryConfig;
import cn.sccl.dirms.topo.discovery.service.DeviceInfoTask;
import cn.sccl.dirms.topo.discovery.service.DiscoveryRelationService;
import cn.sccl.dirms.topo.discovery.util.ComUtil;
import cn.sccl.dirms.topo.discovery.util.Constants;
import cn.sccl.dirms.topo.snmp.mib.IpNetToMediaEntry;
import cn.sccl.dirms.topo.snmp.mib.IpRouteEntry;
import cn.sccl.dirms.topo.snmp.util.SNMPConfig;
import cn.sccl.dirms.topo.util.LogUtil;
import com.alibaba.fastjson.JSONArray;
import org.snmp4j.mp.SnmpConstants;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;


/**
 * Created by liuchuan on 12/29/16.
 */
public class Discovery {
    private ExecutorService service ;
    private List<DeviceInfo> devList = new ArrayList<DeviceInfo>();
    private Map<String,Boolean> haveTestIp = new HashMap<String,Boolean>();
    public List<DeviceInfo> getDevList() {
        return devList;
    }

    public void setDevList(List<DeviceInfo> devList) {
        this.devList = devList;
    }
    /**
     *
     * 创建线程池执行设备发现任务
     *
     * @param ips
     * @param snmpConfigs
     * @param discoveryConfig
     * @return
     */
    public List<DeviceInfo> discoveryDevicesByIps(int threadNum , List<String> ips,
                                                 List<SNMPConfig> snmpConfigs, DiscoveryConfig discoveryConfig) {

        List<DeviceInfo> deviceInfoList = new ArrayList<DeviceInfo>();
        service =  Executors.newFixedThreadPool(threadNum);
        for (int i=0;i<ips.size();) {
            String ip = ips.get(i);
            service.execute(new DeviceInfoTask(ip, snmpConfigs,deviceInfoList, discoveryConfig));
            i++;
            if(i%threadNum==0){
                if(!service.isShutdown()){
                    service.shutdown();
                }
                try {
                    for (boolean bool = false; !bool; bool = service.awaitTermination(3, TimeUnit.SECONDS));
                    service =  Executors.newFixedThreadPool(threadNum);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        if(!service.isShutdown()){
            service.shutdown();
        }
        try {
            for (boolean bool = false; !bool; bool = service.awaitTermination(3, TimeUnit.SECONDS));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return deviceInfoList;
    }
    /**
     * 立刻停止发现任务
     * @return
     */
    public boolean shutdown(){
        boolean flag ;
        try{
            service.shutdownNow();
            flag = true;
        }catch(Exception e){
            flag = false;
        }
        return flag;
    }


    public static void main(String[] args) throws InterruptedException {
        Discovery test = new Discovery();

        List<String> ips = new ArrayList<String>();
        ips.add("10.206.10.65");
//        ips.add("10.206.10.91");
//        ips.add("10.206.10.74");
//        ips.add("10.206.10.66");
        ips.add("10.206.10.80");
        ips.add("10.206.10.84");
        ips.add("10.206.10.81");
        ips.add("10.206.10.93");

        LogUtil.writeSqllog("total: " + ips.size(), "Device.txt");
        List<SNMPConfig> snmpConfigList = new ArrayList<SNMPConfig>();
        //V1
        SNMPConfig target = new SNMPConfig();
        snmpConfigList.add(target);

        SNMPConfig target2 = new SNMPConfig();
        target2.setReadCommunity("sccl");
        target2.setVersion(SnmpConstants.version2c);
        snmpConfigList.add(target2);

        DiscoveryConfig discoveryConfig = new DiscoveryConfig();
        discoveryConfig.setUsePing(false);
        System.out.println("发现设备：");
        Date date1 = DateUtil.getNow();

        List<DeviceInfo> deviceInfoList = test.discoveryDevicesByIps(1000, ips, snmpConfigList, discoveryConfig);
        //System.out.println("发现关联设备：");
        test.getDevList().addAll(deviceInfoList);
        //test.discoveryChildren(deviceInfoList,snmpConfigList,discoveryConfig);
        //for (DeviceInfo deviceInfo : test.getDevList()) {
        //    System.out.println(deviceInfo.getDeviceIP()+"---macs:"+deviceInfo.getDeviceMacs()+"--"+deviceInfo.getDeviceType());
            //转发表再发现
        //}
        //创建链路
        System.out.println(JSONArray.toJSON(deviceInfoList));
        DiscoveryRelationService relation = new DiscoveryRelationService();
       // 发现原始关联关系
        System.out.println("-----------原始链接-----------------------------------------------------：");

//        List<LinkInfo> linkInfoList = relation.createAllLinks(test.getDevList(), discoveryConfig);
//        for (LinkInfo linkInfo : linkInfoList) {
//            System.out.println(""+linkInfo.startDevice.getDeviceIP()+"【"+linkInfo.startDevice.getDeviceName()+"】"+"【"+linkInfo.startPort+"】"+"--------"+linkInfo.endDevice.getDeviceIP()+"【"+linkInfo.endDevice.getDeviceName()+"】"+"【"+linkInfo.endPort+"】");
//
//        }
//        System.out.println("-----------化解之后链接-----------------------------------------------------：");
//
//        List<LinkInfo> oolinkInfoList = DiscoveryAPI.linkDeiscovery(test.getDevList(),discoveryConfig);
//        for (LinkInfo linkInfo : oolinkInfoList) {
//            System.out.println(""+linkInfo.startDevice.getDeviceIP()
//                    +"【"+linkInfo.startDevice.getDeviceName()+
//                    "】"+"【"+linkInfo.startPort+"】"+"--------"+linkInfo.endDevice.getDeviceIP()
//                    +"【"+linkInfo.endDevice.getDeviceName()+"】"+"【"+linkInfo.endPort+"】");
//        }
//        Date date2 = DateUtil.getNow();
//        System.out.println("耗时：" + (date2.getTime() - date1.getTime()) / 1000 + "秒");

    }

    /**
     * 递归发现关联设备 包括 转发表-ARP 路由表
     *
     * @param parentList
     * @param snmpConfigList
     * @param discoveryConfig
     */
    public void discoveryChildren(List<DeviceInfo> parentList,List<SNMPConfig> snmpConfigList,DiscoveryConfig discoveryConfig){

        Discovery discovery = new Discovery();
        List<String> ips = new ArrayList<String>();

        for(DeviceInfo parent:parentList){
            if(!Constants.DeviceTypeRouter.equals(parent.getDeviceType())
                    &&!Constants.DeviceTypeRouter.equals(parent.getDeviceType())){
                continue;//非交换机和路由器不进行查找
            }
            List<IpNetToMediaEntry> addrTable = parent.getIpNetToMediaEntries();
            this.haveTestIp.put(parent.getDeviceIP(),true);
            //根据转发表漫游搜索
            for(IpNetToMediaEntry ipNetToMediaEntry:addrTable) {
                String ip = ipNetToMediaEntry.getIpNetToMediaNetAddress();
                if(!parent.getDeviceIP().equals(ip)&&this.haveTestIp.get(ip)==null&&!ComUtil.ipOnList(ip, this.getDevList())) {
                    this.haveTestIp.put(ip,true);
                    ips.add(ip);
                }
            }
            //根据路由表搜索
            List<IpRouteEntry> routerTable = parent.getIpRouteEntries();
            for(IpRouteEntry ipRouteEntry:routerTable) {
                String ip = ipRouteEntry.getIpRouteNextHop();
                if(!ip.equals(parent.getDeviceIP())&&this.haveTestIp.get(ip)==null&&!ComUtil.ipOnList(ip, this.getDevList())) {
                    this.haveTestIp.put(ip,true);
                    ips.add(ip);
                }
            }
            System.out.println("发现"+parent.getDeviceIP()+"转发表目标IP设备:"+ips.size()+"个");

        }

        //去重
        ComUtil.removeDuplicate(ips);

        List<DeviceInfo> deviceInfoList = discovery.discoveryDevicesByIps(1000,ips, snmpConfigList,discoveryConfig);
        this.devList.addAll(deviceInfoList);
        //递归
        if(deviceInfoList!=null&&deviceInfoList.size()>0){
            discoveryChildren(deviceInfoList,snmpConfigList,discoveryConfig);
        }
    }
}
